import pandas as pd
import numpy as np

'''
构造数组
'''
n = np.array([1,2,3])
print(n)

'''
等差数列
'''
a = np.linspace(1,5,11)
print(a)

'''
特殊矩阵
'''
jz = np.zeros(3)
print(jz)

'''
单位矩阵
'''
dwjz = np.eye(3)
print(dwjz)

'''
偏移对角阵
'''
py = np.eye(3,k=1)
print(py)

'''
初始化矩阵
'''
inint_jz = np.full((2,3),10)
print(inint_jz)
inint_jz = np.full((2,3),[1,2,3])
print(inint_jz)

'''
随机矩阵：均匀分布
0-1 之内的均匀分布的矩阵
'''
r = np.random.rand(3)
r1 = np.random.rand(3,3)

'''
自定义区间的均匀分布
'''
a,b = 5,15
r2 = (b-a)*np.random.rand(3)+a
print(r2)

'''
自定义区间的均匀分布函数
'''
r3 = np.random.uniform(5,15,3)

'''
randn 生成了 0.1 的标准正态分布：
'''
rn = np.random.randn(3)
rn1 = np.random.randn(2,2)
print(rn)
print(rn1)

'''
自定义的方差均值的正态分布
'''
sigma,mu = 2.5,3
s1 = mu+sigma*np.random.randn(3)
print(s1)

'''
直接调用库
'''
s2 = np.random.normal(3,2.5,3)
print(s2)

'''
生成整数的随机值 2*2 的5-15 之间的整数
'''
int_jz = np.random.randint(5,15,(2,2))
print(int_jz)

'''
choice 有放回采样
'''
my_list = ['a','b','c','d']
p1 = np.random.choice(my_list,2,replace=False,p=[0.1,0.7,0.1,0.1])
print(p1)
p2 = np.random.choice(my_list,(3,3))
print(p2)
'''
不放回采样
'''
permutation = np.random.permutation(my_list)
print(permutation)

'''
固定随机种子
'''
np.random.seed(0)
s = np.random.rand()
print(s)

'''
数组的变形和合并
'''
t = np.zeros((2,3)).T
print("转置矩阵",t)

'''
r_ c_ 分别代表上下合并和左右合并
'''
np.r_[np.zeros((2,3)),np.zeros((2,3))]
np.c_[np.zeros((2,3)),np.zeros((2,3))]

'''
一维数组和二维数组进行合并时，应当把其视作列向量，在长度匹配的情况下只能够使用左右合并的 c_ 
'''
np.r_[np.array([0,0]),np.zeros(2)]
np.c_[np.array([0,0]),np.zeros((2,3))]

'''
reshape 能够帮助用户把原数组按照新的维度重新排列。在使用时有两种模式，分别为 C 模式和 F 模式，分别以逐行和逐列的顺序进行填充读取
'''
target = np.arange(8).reshape(2,4)
target.reshape((4,2), order='C') # 按照行读取和填充
target.reshape((4,2), order='F') # 按照列读取和填充
target.reshape((4,-1))
target = np.ones((3,1))
target.reshape(-1)

'''
切片索引
数组的切片模式支持使用 slice 类型的 start:end:step 切片，还可以直接传入列表指定某个维度的索引进行切片
'''
target = np.arange(9).reshape(3,3)
t=target[:-1, [0,1,2]] #取倒数第一个除外的其他
print(t)
# 还可以利用 np.ix_ 在对应的维度上使用布尔索引，但此时不能使用 slice 切片
target[np.ix_([True, False, True], [True, False, True])]
target[np.ix_([1,2], [True, False, True])]

new = target.reshape(-1) # 变成一维数组
n = new[new%2==0]


'''
条件函数
'''
a = np.array([-1,1,-1,0])
np.where(a>0, a, 5) # 对应位置为True时填充a对应元素，否则填充5

'''
这三个函数返回的都是索引， nonzero 返回非零数的索引， argmax, argmin 分别返回最大和最小数的索引
'''
a = np.array([-2,-5,0,1,3,-1])
np.nonzero(a)

'''
any 指当序列至少 存在一个 True 或非零元素时返回 True ，否则返回 False

all 指当序列元素 全为 True 或非零元素时返回 True ，否则返回 False 
'''
a = np.array([0,1])
a.any() # True
a.all()

'''
cumprod, cumsum 分别表示累乘和累加函数，返回同长度的数组， diff 表示和前一个元素做差，由于第一个元素为缺失值，因此在默认参数情况下，返回长度是原数组减1
'''
a = np.array([1,2,3])
a.cumprod()
a.cumsum()
np.diff(a) # 差值


target = np.arange(5)
np.quantile(target, 0.5) # 0.5分位数 为2
'''
但是对于含有缺失值的数组，它们返回的结果也是缺失值，如果需要略过缺失值，必须使用 nan* 类型的函数，上述的几个统计函数都有对应的 nan* 函数
'''
target = np.array([1, 2, np.nan])

'''
协方差和相关系数
可以利用 cov, corrcoef
'''
target1 = np.array([1,3,5,9])
target2 = np.array([1,5,3,-9])
np.cov(target1, target2)

'''
需要说明二维 Numpy 数组中统计函数的 axis 参数，它能够进行某一个维度下的统计特征计算，当 axis=0 时结果为列的统计指标，当 axis=1 时结果为行的统计指标
'''
target = np.arange(1,10).reshape(3,-1)
target.sum(0)
target.sum(1)

'''
广播机制用于处理两个不同维度数组之间的操作，这里只讨论不超过两维的数组广播机制
'''
res = 3 * np.ones((2,2)) + 1

'''
当两个数组维度完全一致时，使用对应元素的操作，否则会报错，除非其中的某个数组的维度是  或者  ，那么会扩充其具有  的维度为另一个数组对应维度的大小。例如，  数组和  数组做逐元素运算时会把第一个数组扩充为  ，扩充时的对应数值进行赋值。但是，需要注意的是，如果第一个数组的维度是  ，那么由于在第二维上的大小不匹配且不为  ，此时报错。
'''
res = np.ones((3,2))
res * np.array([[2,3]]) # 第二个数组扩充第一维度为3
res * np.array([[2],[3],[4]]) # 第二个数组扩充第二维度为2
res * np.array([[2]]) # 等价于两次扩充，第二个数组两个维度分别扩充为3和2

'''
向量与矩阵的计算
'''
a = np.array([1,2,3])
b = np.array([1,3,5])
a.dot(b) # 22


'''
向量范数和矩阵范数： np.linalg.norm
'''
matrix_target =  np.arange(4).reshape(-1,2)
np.linalg.norm(matrix_target, 'fro')

# 练习
M1 = np.random.rand(2,3)
M2 = np.random.rand(3,4)
res = np.empty((M1.shape[0],M2.shape[1]))
for i in range(M1.shape[0]):
    for j in range(M2.shape[1]):
        item = 0
        for k in range(M1.shape[1]):
            item += M1[i][k] * M2[k][j]
        res[i][j] = item
res = [[sum([M1[i][k] * M2[k][j] for k in range(M1.shape[1])]) for j in range(M2.shape[1])] for i in range(M1.shape[0])]
#2
A = np.arange(9)+1
print(A)
A = A.reshape((3,3))
print(A)
print(1/A)
print((1/A).sum(1))
B = 5*(1/A).sum(1)
print(B)
B = A*(1/A).sum(1)
print(B)

#3
np.random.seed(0)

A = np.random.randint(10, 20, (8, 5))

B = A.sum(0)*A.sum(1).reshape(-1, 1)/A.sum()

res = ((A-B)**2/B).sum()

#4
np.random.seed(0)
m,n,p = 100,80,50
B = np.random.randint(0,2,(m,p))
U = np.random.randint(0,2,(p,n))
Z = np.random.randint(0,2,(m,n))
def solution(B=B, U=U, Z=Z):
    L_res = []
    for i in range(m):
        for j in range(n):
            norm_value = ((B[i]-U[:,j])**2).sum()
            L_res.append(norm_value*Z[i][j])
    return sum(L_res)
#5
f = lambda x:np.diff(np.nonzero(np.r_[1,np.diff(x)!=1,1])).max()

f([1,2,5,6,7])


f([3,2,1,2,3,4,6])
print(np.diff([3,2,1,2,3,4,6]))
print(np.diff([3,2,1,2,3,4,6])!=1)
print(np.r_[1,np.diff([3,2,1,2,3,4,6])!=1,1])
print(np.nonzero(np.r_[1,np.diff([3,2,1,2,3,4,6])!=1,1]))

